Skip to content

plugin: granular streaming hooks (P3, retargeted) — on-turn-start/end + on-message-update - #43

Merged
yogthos merged 1 commit into
mainfrom
feat/plugin-streaming-hooks
May 20, 2026
Merged

plugin: granular streaming hooks (P3, retargeted) — on-turn-start/end + on-message-update#43
yogthos merged 1 commit into
mainfrom
feat/plugin-streaming-hooks

Conversation

@yogthos

@yogthos yogthos commented May 20, 2026

Copy link
Copy Markdown
Collaborator

Re-opening PR #38 after its base branch was deleted by the P0 merge. Content unchanged — just retargeted to current main.

Builds on P0's turn-boundary detection. Wires the new
AgentEvent::TurnStart / TurnEnd events into three new plugin hooks:

  on-turn-start     {:index N}
  on-message-update {:index N :partial "text-so-far"}
  on-turn-end       {:index N :message "full turn text"}

These give plugins per-turn observability that wasn't possible from
the previous `on-response` hook alone (which only fires once at the
end of the whole agent run). Typical uses:

* Per-turn cost / latency tracking.
* Token-level filtering or annotation.
* Cancel-on-condition based on streaming output.
* Streaming a live transcript to an external sink.

Implementation:

* `src/ui/streaming.rs` — new TokenBatcher type that collects tokens
  since the last flush and yields the accumulated text once the count
  threshold (DEFAULT_BATCH_TOKENS = 16) is crossed. Count-based
  rather than time-based so the tests are deterministic without
  mocking Instant. Module is cfg-gated to the plugin feature.
* `src/ui/mod.rs`:
  - New per-turn streaming state (token_batcher, current_turn_text,
    current_turn_index), cfg-gated.
  - AgentEvent::Token arm now pushes to the batcher; on flush,
    dispatches `on-message-update` with the accumulated text.
  - AgentEvent::TurnStart arm resets per-turn state and dispatches
    `on-turn-start`.
  - AgentEvent::TurnEnd arm flushes any trailing partial batch (as
    a final `on-message-update`), then dispatches `on-turn-end`
    with the full turn text.
* `src/main.rs` — adds the three hook names to auto-discovery.

`harness/replace-message` (mutating the persisted assistant text from
on-message-end) is deferred. It needs session-write position tracking
and interacts with usage accounting; will land in a follow-up phase.

Tests: 6 new unit tests on `TokenBatcher` — threshold yielding,
post-flush fresh batch, partial-batch draining, reset, zero-threshold
clamping, lossless content over a run. Total: 516 pass with plugin
(was 510); 460/12 baseline without plugin unchanged.

plugins/turn_timing.janet — example using on-turn-start / on-turn-end
to notify the user how long each turn took.

Refs dirge-87x.
@yogthos
yogthos merged commit 5ff15d0 into main May 20, 2026
1 check passed
@yogthos
yogthos deleted the feat/plugin-streaming-hooks branch May 20, 2026 16:46
allen-munsch pushed a commit to allen-munsch/dirge that referenced this pull request Jun 3, 2026
…te) (dirge-code#43)

Builds on P0's turn-boundary detection. Wires the new
AgentEvent::TurnStart / TurnEnd events into three new plugin hooks:

  on-turn-start     {:index N}
  on-message-update {:index N :partial "text-so-far"}
  on-turn-end       {:index N :message "full turn text"}

These give plugins per-turn observability that wasn't possible from
the previous `on-response` hook alone (which only fires once at the
end of the whole agent run). Typical uses:

* Per-turn cost / latency tracking.
* Token-level filtering or annotation.
* Cancel-on-condition based on streaming output.
* Streaming a live transcript to an external sink.

Implementation:

* `src/ui/streaming.rs` — new TokenBatcher type that collects tokens
  since the last flush and yields the accumulated text once the count
  threshold (DEFAULT_BATCH_TOKENS = 16) is crossed. Count-based
  rather than time-based so the tests are deterministic without
  mocking Instant. Module is cfg-gated to the plugin feature.
* `src/ui/mod.rs`:
  - New per-turn streaming state (token_batcher, current_turn_text,
    current_turn_index), cfg-gated.
  - AgentEvent::Token arm now pushes to the batcher; on flush,
    dispatches `on-message-update` with the accumulated text.
  - AgentEvent::TurnStart arm resets per-turn state and dispatches
    `on-turn-start`.
  - AgentEvent::TurnEnd arm flushes any trailing partial batch (as
    a final `on-message-update`), then dispatches `on-turn-end`
    with the full turn text.
* `src/main.rs` — adds the three hook names to auto-discovery.

`harness/replace-message` (mutating the persisted assistant text from
on-message-end) is deferred. It needs session-write position tracking
and interacts with usage accounting; will land in a follow-up phase.

Tests: 6 new unit tests on `TokenBatcher` — threshold yielding,
post-flush fresh batch, partial-batch draining, reset, zero-threshold
clamping, lossless content over a run. Total: 516 pass with plugin
(was 510); 460/12 baseline without plugin unchanged.

plugins/turn_timing.janet — example using on-turn-start / on-turn-end
to notify the user how long each turn took.

Refs dirge-87x.

Co-authored-by: Yogthos <yogthos@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant